﻿using Furion.CMS.Core.Base;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Core.Permission
{
    /// <summary>
    /// 权限定义管理
    /// </summary>
    public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingleton
    {
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 权限组定义
        /// </summary>
        protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value;
        private readonly Lazy<Dictionary<string, PermissionGroupDefinition>> _lazyPermissionGroupDefinitions;

        /// <summary>
        /// 权限定义
        /// </summary>
        protected IDictionary<string, PermissionDefinition> PermissionDefinitions => _lazyPermissionDefinitions.Value;
        private readonly Lazy<Dictionary<string, PermissionDefinition>> _lazyPermissionDefinitions;

        public PermissionDefinitionManager(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;

            _lazyPermissionDefinitions = new Lazy<Dictionary<string, PermissionDefinition>>(
                CreatePermissionDefinitions,
                isThreadSafe: true
            );

            _lazyPermissionGroupDefinitions = new Lazy<Dictionary<string, PermissionGroupDefinition>>(
                CreatePermissionGroupDefinitions,
                isThreadSafe: true
            );
        }

        public PermissionDefinition Get(string name)
        {
            PermissionDefinitions.TryGetValue(name, out PermissionDefinition permission);
            return permission;
        }

        public IReadOnlyList<PermissionGroupDefinition> GetGroups()
        {
            return PermissionGroupDefinitions.Values.ToImmutableList();
        }

        public IReadOnlyList<PermissionDefinition> GetPermissions()
        {
            return PermissionDefinitions.Values.ToImmutableList();
        }

        protected virtual Dictionary<string, PermissionDefinition> CreatePermissionDefinitions()
        {
            var permissions = new Dictionary<string, PermissionDefinition>();

            foreach (var groupDefinition in PermissionGroupDefinitions.Values)
            {
                foreach (var permission in groupDefinition.Permissions)
                {
                    AddPermissionToDictionaryRecursively(permissions, permission.Value);
                }
            }

            return permissions;
        }

        protected virtual void AddPermissionToDictionaryRecursively(Dictionary<string, PermissionDefinition> permissions, PermissionDefinition permission)
        {
            if (permissions.ContainsKey(permission.Name))
            {
                throw Oops.Bah("Duplicate permission name: " + permission.Name);
            }

            permissions[permission.Name] = permission;

            //foreach (var child in permission.Children)
            //{
            //    AddPermissionToDictionaryRecursively(permissions, child);
            //}
        }

        protected virtual Dictionary<string, PermissionGroupDefinition> CreatePermissionGroupDefinitions()
        {
            // 创建作用域
            using (var scope = _serviceProvider.CreateScope())
            {
                var providers = scope.ServiceProvider.GetServices<IPermissionDefinitionProvider>().ToList();

                var context = new PermissionDefinitionContext(scope.ServiceProvider);

                foreach (var provider in providers)
                {
                    provider.PreDefine(context);
                }

                foreach (var provider in providers)
                {
                    provider.Define(context);
                }

                foreach (var provider in providers)
                {
                    provider.PostDefine(context);
                }

                // TODO:额外加载标识了SecurityDefineAttribute 但是未进行权限定义的控制器

                return context.Groups;
            }
        }
    }
}
